package com.bright.ghj.common.util;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @Author hxj
 * @Date 2024/3/6 20:21
 * @Description
 */
public class FileUtil {

    // 判断文件类型 通过文件头 （无法避免伪造文件头的情形）
    public final static Map<String, String> FILE_TYPE_MAP = new LinkedHashMap<>();

    /*-----------------------------目前可以识别的类型----------------------------*/
    static
    {
        FILE_TYPE_MAP.put("jpg", "FFD8FF"); //JPEG
        FILE_TYPE_MAP.put("png", "89504E47"); //PNG
        FILE_TYPE_MAP.put("gif", "47494638"); //GIF
        FILE_TYPE_MAP.put("tif", "49492A00"); //TIFF
        FILE_TYPE_MAP.put("bmp", "424D"); //Windows Bitmap
//        FILE_TYPE_MAP.put("dwg", "41433130"); //CAD
//        FILE_TYPE_MAP.put("html", "68746D6C3E"); //HTML
        FILE_TYPE_MAP.put("rtf", "7B5C727466"); //Rich Text Format
        FILE_TYPE_MAP.put("xml", "3C3F786D6C");
        FILE_TYPE_MAP.put("rar", "52617221");
        FILE_TYPE_MAP.put("psd", "38425053"); //PhotoShop
        FILE_TYPE_MAP.put("eml", "44656C69766572792D646174653A"); //Email [thorough only]
        FILE_TYPE_MAP.put("dbx", "CFAD12FEC5FD746F"); //Outlook Express
        FILE_TYPE_MAP.put("pst", "2142444E"); //Outlook
        FILE_TYPE_MAP.put("office", "D0CF11E0"); //office类型，包括doc、xls和ppt
        FILE_TYPE_MAP.put("zip", "504B0304"); //office新类型（docx,xlsx,pptx等）跟zip的开头码一样，需要再进一步区分
        FILE_TYPE_MAP.put("mdb", "000100005374616E64617264204A"); //MS Access
//        FILE_TYPE_MAP.put("wpd", "FF575043"); //WordPerfect
//        FILE_TYPE_MAP.put("eps", "252150532D41646F6265");
//        FILE_TYPE_MAP.put("ps", "252150532D41646F6265");
        FILE_TYPE_MAP.put("pdf", "255044462D312E"); //Adobe Acrobat
//        FILE_TYPE_MAP.put("qdf", "AC9EBD8F"); //Quicken
//        FILE_TYPE_MAP.put("pwl", "E3828596"); //Windows Password
//        FILE_TYPE_MAP.put("wav", "57415645"); //Wave
//        FILE_TYPE_MAP.put("avi", "41564920");
//        FILE_TYPE_MAP.put("ram", "2E7261FD"); //Real Audio
//        FILE_TYPE_MAP.put("rm", "2E524D46"); //Real Media
//        FILE_TYPE_MAP.put("mpg", "000001BA"); //
//        FILE_TYPE_MAP.put("mov", "6D6F6F76"); //Quicktime
//        FILE_TYPE_MAP.put("asf", "3026B2758E66CF11"); //Windows Media
//        FILE_TYPE_MAP.put("mid", "4D546864"); //MIDI (mid)
    }

    public static String getFileTypeByInputStream(InputStream is, String fileName) throws Exception {
        String fileExtendName = null;
        byte[] b = new byte[16];
        is.read(b, 0, b.length);
        String filetypeHex = String.valueOf(bytesToHexString(b));
        for (Map.Entry<String, String> entry : FILE_TYPE_MAP.entrySet()) {
            String fileTypeHexValue = entry.getValue();
            if (filetypeHex.toUpperCase().startsWith(fileTypeHexValue)) {
                fileExtendName = entry.getKey();
                if (fileExtendName.equals("office")) {
                    fileExtendName = getOfficeFileType(is);
                } else if (fileExtendName.equals("zip")) {
                    // xlsx docx等都会被识别为zip 只能根据文件后缀名来区分
                    String fileSuffix = getFileSuffix(fileName, false);
                    if (StringUtil.equalsIgnoreCase(fileSuffix, "docx")) {
                        fileExtendName = "docx";
                    } else if (StringUtil.equalsIgnoreCase(fileSuffix, "xlsx")) {
                        fileExtendName = "xlsx";
                    } else if (StringUtil.equalsIgnoreCase(fileSuffix, "pptx")) {
                        fileExtendName = "pptx";
                    }
                }
                is.close();
                break;
            }
        }
        return fileExtendName;
    }

    /**
     * 判断office文件的具体类型
     */
    private static String getOfficeFileType(InputStream fileInputStream) throws Exception{
        String officeFileType = "doc";
        byte[] b = new byte[512];
        fileInputStream.read(b, 0, b.length);
        String filetypeHex = String.valueOf(bytesToHexString(b));
        String flagString = filetypeHex.substring(992);
        if(flagString.toLowerCase().startsWith("eca5c")){
            officeFileType = "doc";
        } else if(flagString.toLowerCase().startsWith("fdffffff")){
            officeFileType = "xls";

        } else if(flagString.toLowerCase().startsWith("09081000000")){
            officeFileType = "xls";
        } else {
            officeFileType = "ppt";
        }
        return officeFileType;

    }

    /**
     * 获得文件头部字符串
     */
    private static String bytesToHexString(byte[] src){
        StringBuilder stringBuilder = new StringBuilder();
        if (src == null || src.length <= 0) {
            return null;
        }
        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }

    /**
     * 获取文件后缀名
     * @param fileName
     * @param isWithDot
     * @return
     */
    public static String getFileSuffix(String fileName, boolean isWithDot) {

        int index = fileName.lastIndexOf(".");
        if (!isWithDot) {
            // isWithDot为true时，获取后缀名带上点，如".jpg"
            index += 1;
        }
        return fileName.substring(index);
    }

    public static String getContentTypeByURL(String fileUrlString) {
        String filePrefix = getFileSuffix(fileUrlString, false);
        return getContentTypeBySuffix(filePrefix);
    }


    /**
     * 获取文件类型，如“image/png”
     * @param fileSuffix
     * @return
     */
    public static String getContentTypeBySuffix(String fileSuffix) {
        String rvalue = "";

        if (fileSuffix.equalsIgnoreCase("png")) {
            rvalue = "image/png";
        } else if (fileSuffix.equalsIgnoreCase("jpg") || fileSuffix.equalsIgnoreCase("jpeg")) {
            rvalue = "image/jpeg";
        } else if (fileSuffix.equalsIgnoreCase("pdf")) {
            rvalue = "application/pdf";
        } else if (fileSuffix.equalsIgnoreCase("doc")) {
            rvalue = "application/msword";
        } else if (fileSuffix.equalsIgnoreCase("docx")) {// docx
            rvalue = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
        } else if (fileSuffix.equalsIgnoreCase("xls")) {// xls
            rvalue = "application/vnd.ms-excel";
        } else if (fileSuffix.equalsIgnoreCase("xlsx")) {// xlsx
            rvalue = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
        } else if (fileSuffix.equalsIgnoreCase("zip")) {// zip
            rvalue = "application/zip";
        } else if (fileSuffix.equalsIgnoreCase("rar")) {// rar
            rvalue = "application/x-rar-compressed";
        } else if (fileSuffix.equalsIgnoreCase("7z")) {
            rvalue = "application/x-7z-compressed";
        } else if (fileSuffix.equalsIgnoreCase("webp")) {
            rvalue = "image/webp";
        } else if (fileSuffix.equalsIgnoreCase("bmp")) {
            rvalue = "image/x-ms-bmp";
        } else if (fileSuffix.equalsIgnoreCase("txt")) {
            rvalue = "text/plain";
        } else if (fileSuffix.equalsIgnoreCase("ico")) {
            rvalue = "image/x-icon";
        } else if (fileSuffix.equalsIgnoreCase("tif") || fileSuffix.equalsIgnoreCase("tiff")) {
            rvalue = "image/tiff";
        } else {
//            logger.info("获取文件getContentType：不支持的文件类型——" + filePrefix);
            System.out.println("获取文件getContentType：不支持的文件类型——" + fileSuffix);
        }

        return rvalue;
    }


    public static byte[] getFileBytesFromURL(String fileUrlString) {
        InputStream inputStream = null;
        ByteArrayOutputStream bos = null;

        try {
            URL fileUrl = new URL(fileUrlString);

            URLConnection urlConnection = fileUrl.openConnection();
            inputStream = urlConnection.getInputStream();
            byte[] buffer = new byte[4*1024];
            int len = 0;
            bos = new ByteArrayOutputStream();
            while((len = inputStream.read(buffer)) != -1) {
                bos.write(buffer, 0, len);
            }

            return bos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
//            log.error(e.getMessage());
            // 获取附件失败
            return null;
        } finally {
            try {
                if (inputStream != null) inputStream.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
            try {
                if (bos != null) bos.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }


    }

}
